package com.lry.basic.spring.aop.core;

import com.lry.basic.spring.aop.face.Advisor;
import com.lry.basic.spring.aop.face.AopProxy;
import com.lry.basic.spring.ioc.BeanDefinition;
import com.lry.basic.spring.ioc.BeanFactory;
import com.lry.basic.spring.ioc.DefaultBeanFactory;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.assertj.core.util.Arrays;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;

/**
 * @author:刘仁有
 * @desc:
 * @email:953506233@qq.com
 * @data:2019/11/8
 */
public class CglibDynamicAopProxy implements AopProxy, MethodInterceptor{
    private static Enhancer enhancer = new Enhancer();
    private String beanName;
    private Object target; //目标对象
    private List<Advisor>matchAdvisors;
    private BeanFactory beanFactory;
    public CglibDynamicAopProxy(String beanName, Object target, List<Advisor> matchAdvisors, BeanFactory beanFactory) {
        super();
        this.beanName = beanName;
        this.target = target;
        this.matchAdvisors = matchAdvisors;
        this.beanFactory = beanFactory;
    }

    @Override
    public Object getProxy() {
        return this.getProxy(target.getClass().getClassLoader());
    }

    @Override
    public Object getProxy(ClassLoader classLoader) {
        Class<?> superClass = this.target.getClass();
        enhancer.setSuperclass(superClass);
        enhancer.setInterfaces(this.getClass().getInterfaces());
        enhancer.setCallback(this);
        Constructor<?> constructor = null;
        try {
            constructor = superClass.getConstructor(new Class<?>[]{}) ;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        if(constructor!=null){
            return enhancer.create();
        }else{
            BeanDefinition bd = ((DefaultBeanFactory) beanFactory).getBeanDefinition(beanName);
            return enhancer.create(bd.getConstructor().getParameterTypes(), bd.getConstructorArgumentRealValues());
        }
    }

    /**
     *
     * @param proxy cglib代理对象
     * @param method 目标方法
     * @param args 目标方法 参数
     * @param methodProxy cglib代理方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        //目标对象，目标方法，目标方法参数，匹配的切面，cglib代理对象，bean工厂
        return AopProxyUtils.applyAdvices(target, method, args, matchAdvisors, proxy, beanFactory);
    }
}
